////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
//  All Rights Reserved. The following is Source Code and is subject to all
//  restrictions on such code as contained in the End User License Agreement
//  accompanying this product.
//
////////////////////////////////////////////////////////////////////////////////

package mx.charts.series
{

import flash.display.DisplayObject;
import mx.charts.HitData;
import mx.charts.chartClasses.ChartBase;
import mx.charts.chartClasses.IChartElement;
import mx.charts.chartClasses.IColumn;
import mx.charts.chartClasses.IStackable;
import mx.charts.chartClasses.Series;
import mx.charts.chartClasses.StackedSeries;
import mx.collections.CursorBookmark;
import mx.core.mx_internal;
import mx.charts.chartClasses.CartesianTransform;
import mx.charts.series.items.ColumnSeriesItem;
import mx.charts.chartClasses.IAxis;

use namespace mx_internal;

[DefaultProperty("series")]

/**
 *  ColumnSet is a grouping set that can be used to stack or cluster column series in any arbitrary chart. A ColumnSet encapsulates the same grouping behavior used in a ColumnChart, but can be used to assemble custom charts based on
 *	CartesianChart.
 *  ColumnSets can be used to cluster any chart element type that implements the IColumn interface. It can stack any chart element type that implements the IColumn and IStackable interfaces.  
 *	Since ColumnSet itself implements the IColumn interface, you can use ColumnSets to cluster other ColumnSets to build more advanced custom charts.
 */
public class ColumnSet extends StackedSeries implements IColumn
{
    include "../../core/Version.as";

	//--------------------------------------------------------------------------
	//
	//  Constructor
	//
	//--------------------------------------------------------------------------

	/**
	 *	Constructor.
	 */
	public function ColumnSet()
	{
		super();
	}
	
	//--------------------------------------------------------------------------
	//
	//  Variables
	//
	//--------------------------------------------------------------------------
	
	/**
	 *  @private
	 */
	private var _perColumnWidthRatio:Number;

	/**
	 *  @private
	 */
	private var _perColumnMaxColumnWidth:Number;

	/**
	 *  @private
	 */
	private var _leftOffset:Number;
	
	//--------------------------------------------------------------------------
	//
	//  Properties
	//
	//--------------------------------------------------------------------------
	
    //----------------------------------
	//  columnWidthRatio
    //----------------------------------

	/**
	 *  @private
	 */
	private var _columnWidthRatio:Number = 0.65;

	[Inspectable(category="General")]
	
	/**
	 *  Specifies the width of columns relative to the category width. A value of <code>1</code> uses the entire space, while a value of <code>.6</code> 
	 *  uses 60% of the column's available space. 
	 *  You typically do not set this property directly. 
	 *  The actual column width used is the smaller of <code>columnWidthRatio</code> and the <code>maxColumnWidth</code> property
	 *  
	 *  @default 0.65
	 */
	public function get columnWidthRatio():Number 
	{
		return _columnWidthRatio;
	}	
	
	/**
	 *  @private
	 */
	public function set columnWidthRatio(value:Number):void
	{
		_columnWidthRatio = value;

		invalidateSeries();
	}

    //----------------------------------
	//  maxColumnWidth
    //----------------------------------

	/**
	 *  @private
	 */
	private var _maxColumnWidth:Number;

	[Inspectable(category="General")]
	
	/**
	 *  Specifies the width of the columns, in pixels. The actual column width used is the smaller of this style and the <code>columnWidthRatio</code> property.
	 *  Clustered columns divide this space proportionally among the columns in each cluster. 
	 */
	public function get maxColumnWidth():Number
	{
		return _maxColumnWidth;
	}	
	
	/**
	 *  @private
	 */
	public function set maxColumnWidth(value:Number):void
	{
		_maxColumnWidth = value;

		invalidateSeries();
	}

    //----------------------------------
	//  offset
    //----------------------------------

	/**
	 *  @private
	 */
	private var _offset:Number = 0;

	[Inspectable(category="General")]
	
	/**
	 *  Specifies how far to offset the center of the columns from the center of the available space, relative to the category width. 
	 *  At the value of default <code>0</code>, the columns are centered on the space.
	 *  Set to <code>-50</code> to center the column at the beginning of the available space.
	 *  You typically do not set this property directly. The ColumnChart control manages this value based on 
	 *  its <code>columnWidthRatio</code> property.
	 */
	public function get offset():Number
	{
		return _offset;
	}	
	
	/**
	 *  @private
	 */
	public function set offset(value:Number):void
	{
		_offset = value;

		invalidateSeries();
	}

	//--------------------------------------------------------------------------
	//
	//  Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 *  @inheritDoc
	 */
	override protected function customizeSeries(glyph:IChartElement,i:uint):void
	{
		var currentSeries:IColumn = IColumn(glyph);
		
		if (!isNaN(_perColumnWidthRatio))
			currentSeries.columnWidthRatio = _perColumnWidthRatio;

		if (!isNaN(_perColumnMaxColumnWidth))
			currentSeries.maxColumnWidth = _perColumnMaxColumnWidth;

		if (type == "clustered")		
			currentSeries.offset = _leftOffset + i*_perColumnWidthRatio;
		else
			currentSeries.offset = offset;
			
		super.customizeSeries(glyph,i);
	}

	/** 
	 *  @inheritDoc
	 */
	override protected function buildSubSeries():void
	{
		var i:int;
		var g : IChartElement;
		
		var series:Array = this.series;
		
		if (type == "100%" || type == "stacked")
		{
			_perColumnWidthRatio = columnWidthRatio;
			_perColumnMaxColumnWidth = maxColumnWidth;
		}
		else
		{
			_perColumnWidthRatio = columnWidthRatio / series.length;
			_perColumnMaxColumnWidth = maxColumnWidth / series.length;
		}
		_leftOffset = offset + (1-columnWidthRatio)/2 + _perColumnWidthRatio/2 - .5;


		while (numChildren > 0)
		{
			removeChildAt(0);
		}
	
		if (type == "stacked" || type == "100%")
		{
			for (i=series.length-1;i >= 0;i--)
			{
				g = IChartElement(series[i]);
				customizeSeries(g,i);
				addChild(g as DisplayObject);
			}
		}
		else
		{
			for (i=0;i<series.length;i++)
			{
				g = IChartElement(series[i]);
				customizeSeries(g,i);
				addChild(g as DisplayObject);
			}
		}
		
		var s:ChartBase = chart;
		if (s)	
			s.invalidateSeriesStyles();
	}

	/**
	 *  @inheritDoc
	 */
	override protected function formatDataTip(hd:HitData):String
	{
		var dt:String = "";
		var elt : IStackable = IStackable(hd.element);
		var item:ColumnSeriesItem = ColumnSeriesItem(hd.chartItem);
		
		var percent:Number;
		
		var total:Number = totalsByPrimaryAxis[item.xValue];

		// now compute the percentage
		if (type == "100%")
		{
			percent = Number(item.yValue) - Number(item.minValue);
			percent = Math.round(percent * 10) / 10;
		}
		else
		{
			var size:Number = Number(item.yValue) - Number(item.minValue);
			percent = Math.round(size / total * 1000) / 10;
		}
		
			

		var n:String = (elt as Series).displayName;
		if (n != null && n.length>0)
			dt += "<b>" + n + "</b><BR/>";

		var hAxis:IAxis = dataTransform.getAxis(CartesianTransform.HORIZONTAL_AXIS);
		var xName:String = hAxis.displayName;
		if (xName != "")
			dt += "<i>" + xName + ":</i> ";
		dt += hAxis.formatForScreen(item.xValue) + "\n";

		var vAxis:IAxis = dataTransform.getAxis(CartesianTransform.VERTICAL_AXIS);
		var yName:String = vAxis.displayName;

		if (yName != "")
			dt += "<i>" + yName + ":</i> ";
		dt += vAxis.formatForScreen(Number(item.yValue) - Number(item.minValue)) + " (" +  percent + "%)\n";
		if (yName != "")
			dt += "<i>" + yName + " (total):</i> ";
		else
			dt += "<i>total:</i> ";
		dt += vAxis.formatForScreen(total);		
		return dt;
	}

	/**
	 *  @inheritDoc
	 */
	override public function describeData(dimension:String, requiredFields:uint) : Array
	{
		var result:Array = super.describeData(dimension,requiredFields);
		if(dimension == CartesianTransform.HORIZONTAL_AXIS && result.length > 0)
		{
			result[0].padding = .5;	
		}
		return result;
	}
	
}


}